package com.ai.service.made.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.ai.async.BatchGetAlgorithmStatusAsync;
import com.ai.async.BatchGetCameraStatusAsync;
import com.ai.common.CommonResponse;
import com.ai.common.constant.AlgorithmConstant;
import com.ai.common.constant.RedisConstants;
import com.ai.common.constant.enumP.CameraDetectStatus;
import com.ai.entity.BasePage;
import com.ai.entity.alarm.*;
import com.ai.entity.function.FunctionPO;
import com.ai.entity.made.camera.CameraPO;
import com.ai.entity.made.camera.CameraVO;
import com.ai.entity.made.page.CameraPage;
import com.ai.mapper.made.CameraMapper;
import com.ai.model.dto.RecordInfoDto;
import com.ai.model.vo.*;
import com.ai.service.made.*;
import com.ai.service.security.ISysUserService;
import com.ai.util.GetCameraInfoHk;
import com.ai.util.SecurityUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @Author：xiaosheng
 * @Date：2024-08-13 11:13
 */
@Service
@Slf4j
public class InformationServiceImpl implements InformationService {

    @Resource
    RecordAlarmService recordAlarmService;

    @Resource
    ISysUserService sysUserService;

    @Resource
    CameraService cameraService;

    @Resource
    IRegionBaseService iRegionBaseService;

    @Resource
    IRegionManageService iRegionManageService;

    @Resource
    CameraMapper cameraMapper;

    @Resource
    FunctionService functionService;

    @Resource
    private IAlgorithmServerRelationService iAlgorithmServerRelationService;

    @Resource
    IRegionManageService regionManageService;


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private GetCameraInfoHk getCameraInfoHk;

    @Resource
    ICameraFlowCollectionPlatformService iCameraFlowCollectionPlatformService;
    @Override
    public CommonResponse getTodayRecordNum(RecordAlarmPage recordAlarmPage) {


        Integer num = recordAlarmService.getTodayRecordNum();
        return CommonResponse.ok(num);

    }


    @Override
    public CommonResponse getWeekRecordNum(RecordAlarmPage recordAlarmPage) {

        Integer num = recordAlarmService.getWeekRecordNum();
        return CommonResponse.ok(num);

    }


    @Override
    public CommonResponse getUserNum() {

        long count = sysUserService.count();

        return CommonResponse.ok(count);
    }

    @Override
    public CommonResponse getCameraNum() {

        List<CameraPO> list = cameraService.list();

        if (list == null || list.isEmpty()) {
            return CommonResponse.error("没有摄像头");
        }

        return CommonResponse.ok(list);
    }

    @Override
    public CommonResponse getRegionBase(CameraPage page) {

        IPage<CameraVO> voIPage = new BasePage<>();
        //获取当前区域管理的摄像头
        HashMap<String, String> cameraRegionMap = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService);

        if (CollectionUtils.isEmpty(cameraRegionMap)) {
            //当前区域没有管理任何摄像头
            return CommonResponse.ok(voIPage);
        }

        List<String> cameraCodes = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService, cameraService, page.getRegionCodes());
        page.setCameraCodes(cameraCodes);
        QueryWrapper<CameraPO> queryWrapper = new QueryWrapper<>();
        queryWrapper = page.getQuery(queryWrapper);
        voIPage = cameraMapper.cameraList(page, queryWrapper);
        return CommonResponse.ok(voIPage);
    }

    /**
     * 按区域统计报警数
     * @return
     */
    @Override
    public CommonResponse getRegionRecord() {
        // 获取所有矿区信息
        List<CoalMineVo> coalMineVoList = regionManageService.treeList();

        if (coalMineVoList == null || coalMineVoList.isEmpty()) {
            return CommonResponse.error("没有矿区信息");
        }

        List<RegionRecordNum> regionRecordNumList = new ArrayList<>();

        //统计各个大矿下面的告警数量信息
        for (CoalMineVo coalMineVo : coalMineVoList) {
            //获取各个大矿下面的子区域
            List<RegionVo> coalMineVoRegions = coalMineVo.getRegions();
            RegionRecordNum regionRecordNum = new RegionRecordNum();
            regionRecordNum.setName(coalMineVo.getMiningAreaName());

            if (CollectionUtils.isEmpty(coalMineVoRegions)){
                //当前大矿下并没有子区域，则表明当前矿的告警数量为空
                regionRecordNum.setValue(0);
                regionRecordNumList.add(regionRecordNum);
                continue;
            }

            //获取所有子矿管理的摄像头code
            List<String>  manageCameraCode = iRegionBaseService.getManageCamera(coalMineVoRegions);
            if (CollectionUtils.isEmpty(manageCameraCode)){
                //当前大矿下并没有分配摄像头
                regionRecordNum.setValue(0);
                regionRecordNumList.add(regionRecordNum);
                continue;
            }

            Integer sumRecord = recordAlarmService.countAlarmByCameraCodes(manageCameraCode);
            regionRecordNum.setValue(sumRecord);
            regionRecordNumList.add(regionRecordNum);

        }

        return CommonResponse.ok(regionRecordNumList);
    }

    @Override
    public CommonResponse getRecordNumByType() {

        List<FunctionRecordNum> functionRecordNums =  recordAlarmService.statisticsAlarmByType();
        return CommonResponse.ok(functionRecordNums);
    }

    @Override
    public CommonResponse getTodayRecordNumAndDetail(RecordInfoDto recordInfoDto) {
        RecordNumAndDetail recordNumAndDetail = new RecordNumAndDetail();

        List<RecordNumAndDetail.RecordDetail> recordDetails =   recordAlarmService.getTodayRecordNumAndDetail(recordInfoDto);

        if (CollectionUtil.isNotEmpty(recordDetails)){
            int sum = recordDetails.stream().mapToInt(RecordNumAndDetail.RecordDetail::getNum)
                    .sum();
            recordNumAndDetail.setAlarmSum( String.format("%05d", sum));
        }
        recordNumAndDetail.setRecordDetails(recordDetails);

        return CommonResponse.ok(recordNumAndDetail);
    }

    @Override
    public CommonResponse getWeekRecordNumAndDetail(RecordInfoDto recordInfoDto) {
        RecordNumAndDetail res = new RecordNumAndDetail();
        List<RecordNumAndDetail.RecordDetail> recordDetails =   recordAlarmService.getWeekRecordNumAndDetail(recordInfoDto);
        res.setRecordDetails(recordDetails);
        if (CollectionUtil.isNotEmpty(recordDetails)){
            int sum = recordDetails.stream().mapToInt(RecordNumAndDetail.RecordDetail::getNum).sum();
            res.setAlarmSum( String.format("%05d", sum));
        }


        return CommonResponse.ok(res);
    }

    @Override
    public CommonResponse getMonthRecordNumAndDetail(RecordInfoDto recordInfoDto) {
        Map<String, List<String>>   res = recordAlarmService.getMonthRecordNumAndDetail(recordInfoDto);
        return CommonResponse.ok(res);
    }

    @Override
    public CommonResponse statisticsOfCameraStatus(RecordInfoDto recordInfoDto) {

        HashMap<String, Long> resMap = new HashMap<>(16);
        resMap.put("running",0L);
        resMap.put("abnormal",0L);

//        getCameraStatusFromPlatFlow(recordInfoDto, resMap);
        getCameraStatusFromAlgorithm(recordInfoDto, resMap);

        return CommonResponse.ok(resMap);
    }


    /**
     * 从算法获取摄像头状态
     * @param recordInfoDto 单位信息
     * @param resMap 结果
     */
    private void getCameraStatusFromAlgorithm(RecordInfoDto recordInfoDto, HashMap<String, Long> resMap){

        List<String> belowRegionIdList = new ArrayList<>();
        if (StrUtil.isNotEmpty((recordInfoDto.getRegionBaseId()))){
            belowRegionIdList  =  iRegionBaseService.getBelowRegionIdList(recordInfoDto.getRegionBaseId());
        }else {
            belowRegionIdList  =  iRegionBaseService.getBelowRegionIdList(SecurityUtils.getLoginRegionBaseId());
        }

        List<CameraPO> cameraPOList = cameraService.list(new QueryWrapper<CameraPO>().in("region_id", belowRegionIdList).ne("state","-1"));
        if(CollectionUtil.isNotEmpty(cameraPOList)){

            List<String> cameraStatusRedisKeyList =
                    cameraPOList.stream().map(cameraPO -> {
                        return RedisConstants.CAMERA_STATUS_ALGORITHM+cameraPO.getId();
                    }).collect(Collectors.toList());


            List<String> multiGetCameraStatus = stringRedisTemplate.opsForValue().multiGet(cameraStatusRedisKeyList);

            Long sum = multiGetCameraStatus.stream()
                    .filter(Objects::nonNull)
                    .mapToLong(Long::parseLong)
                    .sum();

            long unOnlineCameraNum = cameraStatusRedisKeyList.size()-sum;

            resMap.put("running",sum);
            resMap.put("abnormal",unOnlineCameraNum);

        }


    }


    /**
     * 从平台取流获取摄像头状态
     * @param recordInfoDto
     * @param resMap
     */
    private void getCameraStatusFromPlatFlow(RecordInfoDto recordInfoDto, HashMap<String, Long> resMap) {
        //获取当前组织下的非平台取流摄像头数量
        long unPlatFlowCameraNum = 0L;
        //获取当前组织下的取流平台
        List<Integer> belowPlatIdList = new LinkedList<>();
        if (null != recordInfoDto.getRegionBaseId()){
            belowPlatIdList  = iCameraFlowCollectionPlatformService.getBelowPlatId(recordInfoDto.getRegionBaseId());
            unPlatFlowCameraNum =   cameraService.getUnPlatFlowCameraNum(recordInfoDto.getRegionBaseId());
        }else {
            belowPlatIdList  = iCameraFlowCollectionPlatformService.getBelowPlatId(SecurityUtils.getLoginRegionBaseId());
            unPlatFlowCameraNum = cameraService.getUnPlatFlowCameraNum(SecurityUtils.getLoginRegionBaseId());
        }
        resMap.put("running",unPlatFlowCameraNum);

        if (CollectionUtil.isNotEmpty(belowPlatIdList)){

            //获取每个平台下的所有摄像头信息
            List<HashMap<Integer, List<String>>> platCameraCodeMap = belowPlatIdList.stream().map(belowPlatId -> {
                HashMap<Integer, List<String>> map = new HashMap<>(1);
                //获取所有使用该平台取流的摄像头信息
                List<String> cameraCodeList = cameraService.getCameraListByPlatId(belowPlatId);
                map.put(belowPlatId, cameraCodeList);
                return map;
            }).collect(Collectors.toList());

            List<Callable<Map<Integer, Long>>> tasks = new ArrayList<>();
            log.info("创建所有的子任务，一次性提交");
            for (HashMap<Integer, List<String>> integerListHashMap : platCameraCodeMap) {
                integerListHashMap.forEach((platId, cameraCodes) -> {
                    if (CollectionUtil.isNotEmpty(cameraCodes)) {
                        BatchGetCameraStatusAsync.GetCameraStatusFromPlatTask task =
                                new BatchGetCameraStatusAsync.GetCameraStatusFromPlatTask(platId, cameraCodes, getCameraInfoHk);
                        resMap.put("abnormal", resMap.get("abnormal")+ cameraCodes.size());
                        tasks.add(task);
                    }
                });
            }

            log.info("统计摄像头个数：{}", resMap.get("abnormal")+ resMap.get("running"));

            try {
                log.info("===========================  开始执行所有子任务，统计摄像头的在线状态  ===========================");
                List<Future<Map<Integer, Long>>> resFutures = BatchGetCameraStatusAsync.executorService.invokeAll(tasks);

                for (Future<Map<Integer, Long>> future : resFutures) {
                    Map<Integer, Long> integerLongMap = future.get();
                    if (null != integerLongMap.get(CameraDetectStatus.ON_LINE.getCode())){
                        resMap.put("running", resMap.get("running")+ integerLongMap.get(CameraDetectStatus.ON_LINE.getCode()));
                        resMap.put("abnormal", resMap.get("abnormal") - integerLongMap.get(CameraDetectStatus.ON_LINE.getCode()));
                    }
                }
            } catch (InterruptedException e) {
                log.error("异步批量获取摄像头状态，出现异常,{}",e.getMessage());
            } catch (ExecutionException e) {
                log.error("异步获取摄像头状态结果，出现异常,{}",e.getMessage());
            }
        }
    }

    @Override
    public CommonResponse statisticsAlgorithmStatus() {

        HashMap<String, Integer> res = new HashMap<>(16);
        //正在运行的算法
        res.put(AlgorithmConstant.STATUS_RUNNING,0);
        //摘除光流法功能
        List<FunctionPO> functionPOList = functionService.list(new QueryWrapper<FunctionPO>()
                .eq("state", 1)
                .select("id")
                .ne("type",3001));
        //运行异常的算法
        res.put(AlgorithmConstant.STATUS_ABNORMAL,functionPOList.size());


        List<BatchGetAlgorithmStatusAsync.GetAlgorithmStatus> tasks = functionPOList.stream().map(functionPO -> {
            Integer functionPOId = functionPO.getId();
            BatchGetAlgorithmStatusAsync.GetAlgorithmStatus getAlgorithmStatusTask =
                    new BatchGetAlgorithmStatusAsync.GetAlgorithmStatus(functionPOId, iAlgorithmServerRelationService);
            return getAlgorithmStatusTask;
        }).collect(Collectors.toList());

        try {
            List<Future<Integer>> resFuture = BatchGetAlgorithmStatusAsync.executorService.invokeAll(tasks);
            for (Future<Integer> future : resFuture) {
                //算法正在运行的数量
                Integer integer = future.get();
                res.put(AlgorithmConstant.STATUS_RUNNING,res.get(AlgorithmConstant.STATUS_RUNNING)+integer);
                res.put(AlgorithmConstant.STATUS_ABNORMAL,res.get(AlgorithmConstant.STATUS_ABNORMAL)-integer);
            }
        } catch (InterruptedException e) {
            log.error("异步获取算法状态信息任务，出现异常,{}",e.getMessage());
        } catch (ExecutionException e) {
            log.error("异步获取算法状态信息结果，出现异常{}",e.getMessage());
        }


        return CommonResponse.ok(res);
    }
}
